#!/usr/bin/env python
#
# syntax.py is part of pyStrips
# Copyright (C) - 2009 - Juan B. Cabral <jbcabral_89@yahoo.com.ar>

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


################################################################################
# DOCS
################################################################################

'''Validate syntax and create structure for pyStrips.'''


################################################################################
# IMPORTS
################################################################################

import common
import structs
import error


################################################################################
# PRIVATE FUNCTION
################################################################################

def _create_predicates(block):
    preds = []
    for p in block:
        if not common.RE_PREDICATE.match(p):
            msg = "Invalid predicate statement: %s" % p
            raise error.PyStripsError(msg, error.SYNTAX_ERROR, p)
        args = p.split()
        name = args.pop(0)
        preds.append(structs.Predicate(name, args, p))
    return preds
    
            
def _create_state(b_name, block):
    if not common.RE_STATE.match(b_name):
        msg = "Invalid state statement: %s" % b_name
        raise error.PyStripsError(msg, error.SYNTAX_ERROR. b_name)
    rw, type, name = [part for part in b_name.split() if part]
    preds = _create_predicates(block)
    return structs.State(type, name, preds, b_name)
    
    
def _create_op(b_name, block):
    if not common.RE_OPERATOR.match(b_name):
        msg = "Invalid operator statement: %s" % b_name
        raise error.PyStripsError(msg, error.SYNTAX_ERROR. b_name)
    rw, name, args = [part for part in b_name.split(" ", 2)] 
    args = args.split()
    try:
        pre_list = _create_predicates(block.pop(common.RW_LIST_PRECONDITION))
        del_list = _create_predicates(block.pop(common.RW_LIST_DELETE))
        add_list = _create_predicates(block.pop(common.RW_LIST_ADD))
    except KeyError as err:
        msg = "Missing %s list" % str(err)
        raise error.PyStripsError(msg, error.SYNTAX_ERROR, b_name) 
    if block:
        msg = "Invalid Operator list: %s" % ", ".join(block.keys())
        raise error.PyStripsError(msg, error.SYNTAX_ERROR, b_name)
    return structs.Operator(name, args, pre_list, del_list, add_list, b_name)


################################################################################
# PUBLIC FUNCTIONS
################################################################################

def validate(preprocessed_src):
    s_list = []
    for b_name, block in preprocessed_src.items():
        if b_name == common.RW_PREDICATES:
            preds = _create_predicates(block)
            s_list.extend(preds)
        elif b_name.startswith(common.RW_OPERATOR):
            op = _create_op(b_name, block)
            s_list.append(op)
        elif b_name.startswith(common.RW_STATE):
            state = _create_state(b_name, block)
            s_list.append(state)
        else:
            msg = "Unknow statement: %s" % b_name
            raise error.PyStripsError(msg, error.SYNTAX_ERROR)
    return s_list
    

################################################################################
# MAIN
################################################################################

if __name__ == '__main__':
    print __doc__

